package cz.cuni.mff.ufal.volk;

import cz.cuni.mff.ufal.httpserver.protocol.HttpRequest;
import cz.cuni.mff.ufal.httpserver.protocol.HttpResponse;
import cz.cuni.mff.ufal.httpserver.protocol.HttpResponse.Status;

enum NabaztagResource {
  /**
   * The resource requested by Nabaztag after booting. Nabaztag requests the resource until it gets
   * a correct byte code.
   */
  BOOT("/vl/bc.jsp") {
    @Override
    public void process(HttpRequest request, HttpResponse response, NabaztagHttpListener listener) {
      try {
        listener.boot(request, response);
      } catch (MalformedRequestException e) {
        handleMalformedRequestException(e, response);
      }
    }
  },

  /**
   * When Nabaztag has successfully loaded the byte code it first calls locate.jsp which has to tell
   * two IP's for Nabaztag. First IP is pingserver from where p4.jsp is called. After newline next value
   * is broadcast server. Nabaztag will replace all "broadcast" strings from the Message Block with this
   * value when Nabaztag receives message.
   */
  LOCATE("/vl/locate.jsp") {
    @Override
    public void process(HttpRequest request, HttpResponse response, NabaztagHttpListener listener) {
      try {
        listener.locate(request, response);
      } catch (MalformedRequestException e) {
        handleMalformedRequestException(e, response);
      }
    }
  },

  /**
   * Basic ping call from Nabaztag. Ping purpose is to inform the server whether an action has been
   * performed by the user and to inform whether the last message sent from the server has been
   * successfully processed.
   */
  PING("/vl/p4.jsp") {
    @Override
    public void process(HttpRequest request, HttpResponse response, NabaztagHttpListener listener) {
      try {
        listener.ping(request, response);
      } catch (MalformedRequestException e) {
        handleMalformedRequestException(e, response);
      }
    }
  },

  /**
   * When user keeps pressing the button on Nabaztag's head it records the voice. After user has released
   * the button it sends record.jsp call to the server with encoded audio data in its POST part
   * of the message.
   */
  RECORD("/vl/record.jsp") {
    @Override
    public void process(HttpRequest request, HttpResponse response, NabaztagHttpListener listener) {
      try {
        listener.record(request, response);
      } catch (MalformedRequestException e) {
        handleMalformedRequestException(e, response);
      }
    }
  },

  /**
   * After Nabaztag has read the correct type of RFID tag it sends rfid.jsp call to the server.
   * It passes the serial number of the sending Nabaztag, the version of the bytecode and the ID
   * of the RFID. If Nabaztag receives an incorrect ID or the ID is kept in front of Nabaztag
   * so that it repeatetly reads tag then Nabaztag sends zero ID (sixteen zeros in a row).
   */
  RFID("/vl/rfid.jsp") {
    @Override
    public void process(HttpRequest request, HttpResponse response, NabaztagHttpListener listener) {
      listener.rfid(request, response);
    }
  },

  /**
   * Local resource requested.
   */
  LOCAL("/local/") {
    @Override
    public void process(HttpRequest request, HttpResponse response, NabaztagHttpListener listener) {
      listener.localResource(request, response,
          request.getRequestedUri().getPath().substring(LOCAL.path.length()));
    }
  };

  public abstract void process(HttpRequest request, HttpResponse response, NabaztagHttpListener listener);

  protected void handleMalformedRequestException(MalformedRequestException e, HttpResponse response) {
    response.setStatus(Status.BAD_REQUEST); // TODO
    response.writeHeaders();
    response.getPrintWriter().println("bad request");
  }

  private final String path;

  /**
   * @return The resource path.
   */
  public String getPath() {
    return path;
  }

  private NabaztagResource(String path) {
   this.path = path;
  }

  /**
   * Finds and returns the resource representing the given path.
   * @param path
   * @return The resource if found, null otherwise.
   */
  public static NabaztagResource getByPath(String path) {
    for (NabaztagResource res : values()) {
      if (res.path.equals(path)) {
        return res;
      }
    }
    if (path.startsWith(LOCAL.path)) {
      return LOCAL;
    }
    return null;
  }
}
